package core.molecules.organic.glycosylamines;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import core.molecules.IMolecule;
import core.molecules.atoms.Atom;
import core.molecules.organic.OrganicCompound;
import core.molecules.organic.amines.Amine;
import core.molecules.organic.sugars.Sugar;



/**
 * A molecule base for any glycosylamine - compound containing some R-group with a bound amine.
 * @author Julian
 *
 * @param <T>
 * @param <S>
 */
public abstract class Glycosylamine<T extends Sugar, S extends Amine> implements IMolecule {

	@Override
	public boolean equals(IMolecule m) {
		if (!this.getClass().isAssignableFrom(m.getClass()))
			return false;
		return this.equals((Glycosylamine)m);
	}
	
	public boolean equalsLikeType(Glycosylamine<? extends Sugar,? extends  Amine> m) {
		Iterator<OrganicCompound> iter1 = this.getSubMolecules().iterator();
		Iterator<OrganicCompound> iter2 = m.getSubMolecules().iterator();
		while(iter1.hasNext() && iter2.hasNext()){
			if (!iter1.next().equals(iter2.next()))
				return false;
		}
		return true;
	}


	@Override
	public String toString() {
		return "Sugar:\n" + mySugar.toString() +
				"Amine:\n" + myAmine.toString();
	}


	@Override
	public int compareTo(IMolecule o) {
		return this.getID().compareTo(o.getID());
	}

	private int myID;
	private T mySugar;
	private S myAmine;
	

	public Glycosylamine(T sugar, S amine, int id){
		setSugar(sugar);
		setAmine(amine);
		myID = id;
	}
	
	@Override
	public Integer getID(){
		return myID;
	}


	@Override
	public double getMass() {
		return mySugar.getMass() + myAmine.getMass();
	}

	@Override
	public double getNumSubParticle() {
		return mySugar.getNumSubParticle()+myAmine.getNumSubParticle();
	}

	@Override
	public int getOxidationState() {
		return mySugar.getOxidationState() + myAmine.getOxidationState();
	}
	
	@Override
	public boolean isEmpty() {
		
		return mySugar.isEmpty() && myAmine.isEmpty();
	}

	@Override
	public void trimEmptyMolecules() {
		if (mySugar.isEmpty()) mySugar = null;
		else mySugar.trimEmptyMolecules();
		if (myAmine.isEmpty()) myAmine = null;
		else myAmine.trimEmptyMolecules();
	}

	public T getSugar() {
		return mySugar;
	}

	public void setSugar(T sugar) {
		this.mySugar = sugar;
	}

	public S getAmine() {
		return myAmine;
	}

	public void setAmine(S amine) {
		this.myAmine = amine;
	}
	
	/**
	 * Retrieves all subatoms from the components of this glycoslyamine
	 * @return
	 */
	public List<Atom> getAllSubAtoms() {
		List<Atom> allAtoms = new ArrayList<Atom>();
		if (this.getSugar() != null)
			allAtoms.addAll(getSugar());
		if (this.getAmine() != null)
		allAtoms.addAll(getAmine());
		return allAtoms;
	}
	
	/**
	 * Returns an iterable collection of the macro-molecular components of this object
	 * @return
	 */
	public List<OrganicCompound> getSubMolecules(){
		List<OrganicCompound> all = new ArrayList<OrganicCompound>();
		if (this.getAmine() != null)
			all.add(getAmine());
		if (this.getSugar() != null)
			all.add(getSugar());
		return all;
	}

}
